#include <sys_config.h>
#include <types.h>
#include <basic_types.h>
#include <mediatypes.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <osal/osal.h>
#ifndef NEW_DEMO_FRAME
#include <api/libpub29/lib_pub27.h>
#include <api/libpub29/lib_as.h>
#else
#include <api/libpub/lib_frontend.h>
#endif

#include <api/libosd/osd_lib.h>

#ifdef AUDIO_DESCRIPTION_SUPPORT
#include <hld/dmx/dmx.h>
#include <api/libsi/psi_pmt.h>
#include "win_audio_description.h"
#endif

#include "osdobjs_def.h"
#include "string.id"
#include "images.id"
#include "osd_config.h"

#include "menus_root.h"
#include "win_com.h"
#include "win_com_popup.h"
#include "win_com_list.h"
#include "win_signalstatus.h"

#include "mobile_input.h"

#if 0
#define AUDIO_DEBUG(fmt, arg...) libc_printf(fmt, ##arg)
#else
#define AUDIO_DEBUG(...)	do{} while(0)
#endif

/*******************************************************************************
*	Objects definition
*******************************************************************************/
extern CONTAINER g_win_audio;

extern TEXT_FIELD audio_title;
extern TEXT_FIELD audio_txt_mode;

extern OBJLIST 	audio_ol;
extern SCROLL_BAR 	audio_scb;
extern BITMAP	audio_mark;


extern CONTAINER audio_item1;
extern CONTAINER audio_item2;
extern CONTAINER audio_item3;
extern CONTAINER audio_item4;
extern CONTAINER audio_item5;
extern CONTAINER audio_item6;

extern TEXT_FIELD audio_txt1;
extern TEXT_FIELD audio_txt2;
extern TEXT_FIELD audio_txt3;
extern TEXT_FIELD audio_txt4;
extern TEXT_FIELD audio_txt5;
extern TEXT_FIELD audio_txt6;


static VACTION audio_item_keymap(POBJECT_HEAD pObj, UINT32 key);
static PRESULT audio_item_callback(POBJECT_HEAD pObj, VEVENT event, UINT32 param1, UINT32 param2);

static VACTION audio_list_keymap(POBJECT_HEAD pObj, UINT32 key);
static PRESULT audio_list_callback(POBJECT_HEAD pObj, VEVENT event, UINT32 param1, UINT32 param2);

static VACTION audio_keymap(POBJECT_HEAD pObj, UINT32 key);
static PRESULT audio_callback(POBJECT_HEAD pObj, VEVENT event, UINT32 param1, UINT32 param2);

#define WIN_SH_IDX	  WSTL_WIN_SLIST_02_8BIT//WSTL_INFO_01_8BIT//WSTL_ZOOM_WIN_01
#define WIN_HL_IDX	  WIN_SH_IDX//WSTL_ZOOM_WIN_01
#define WIN_SL_IDX	  WIN_SH_IDX//WSTL_ZOOM_WIN_01
#define WIN_GRY_IDX   WIN_SH_IDX//WSTL_ZOOM_WIN_01

#define TITLE_SH_IDX 	WSTL_MIXBACK_IDX_01_8BIT////WSTL_MIXBACK_BLACK_IDX
#define MODE_SH_IDX	    WSTL_AUDIO_WIN_01 //WSTL_VOLUME_01_BG_8BIT //

#define LST_SH_IDX		WSTL_NOSHOW_IDX
#define LST_HL_IDX		WSTL_NOSHOW_IDX
#define LST_SL_IDX		WSTL_NOSHOW_IDX
#define LST_GRY_IDX	WSTL_NOSHOW_IDX
/*
#define CON_SH_IDX   WSTL_TEXT_17
#define CON_HL_IDX   //WSTL_BUTTON_05
#define CON_SL_IDX   WSTL_TEXT_17//WSTL_BUTTON_01
#define CON_GRY_IDX  WSTL_BUTTON_07
*/
#define CON_SH_IDX   WSTL_TEXT_15_8BIT 
#define CON_HL_IDX   WSTL_BUTTON_05_8BIT 
#define CON_SL_IDX   WSTL_TEXT_15_8BIT
#define CON_GRY_IDX  WSTL_TEXT_14


/*
#define TXT_SH_IDX   WSTL_TEXT_17
#define TXT_HL_IDX   WSTL_BUTTON_02_FG
#define TXT_SL_IDX   WSTL_TEXT_17//WSTL_BUTTON_01_FG
#define TXT_GRY_IDX  WSTL_BUTTON_07
*/

#define TXT_SH_IDX   WSTL_TEXT_15_8BIT
#define TXT_HL_IDX   WSTL_TEXT_28_8BIT
#define TXT_SL_IDX   WSTL_TEXT_15_8BIT
#define TXT_GRY_IDX  WSTL_TEXT_14

#define LIST_BAR_SH_IDX  WSTL_SCROLLBAR_01_8BIT//WSTL_SCROLLBAR_01
#define LIST_BAR_HL_IDX  WSTL_SCROLLBAR_01_8BIT//WSTL_SCROLLBAR_01

#define LIST_BAR_MID_RECT_IDX  	WSTL_NOSHOW_IDX
#define LIST_BAR_MID_THUMB_IDX  	WSTL_SCROLLBAR_02_8BIT //WSTL_SCROLLBAR_02

#define MARK_SH_IDX	    WSTL_MIXBACK_IDX_06_8BIT  //WSTL_MIXBACK_BLACK_IDX
#define MARK_HL_IDX	    MARK_SH_IDX             //WSTL_MIXBACK_BLACK_IDX
#define MARK_SL_IDX	    MARK_SH_IDX             //WSTL_MIXBACK_BLACK_IDX
#define MARK_GRY_IDX	MARK_SH_IDX             //WSTL_MIXBACK_BLACK_IDX

#ifndef SD_UI
#define	W_L     74//210
#define	W_T     60//110
#define	W_W     400//260
#define	W_H     350//420//250

#if Maker_GUI_ON
#define TITLE_L  (W_L)
#define TITLE_T	 (W_T)
#define TITLE_W  (W_W)
#define TITLE_H  48//26
#else
#define TITLE_L  (W_L)
#define TITLE_T	 (W_T + 6)
#define TITLE_W  (W_W - 20)
#define TITLE_H  48//26
#endif

#define MODE_L  (W_L+14)
#define MODE_T	(W_T+54) //(TITLE_T + TITLE_H + 2)
#define MODE_W  (W_W-28)
#define MODE_H  36//40


#define LST_L	(W_L + 20)
#define LST_T	(MODE_T +  MODE_H)
#define LST_W	(W_W - 56)
#define LST_H	(W_H - TITLE_H - MODE_H - 26)//240//200 //180

#define SCB_L (LST_L + LST_W + 4)
#define SCB_T LST_T
#define SCB_W 12
#define SCB_H LST_H//(LST_H - 36)

#define CON_L	LST_L
#define CON_T	LST_T
#define CON_W	LST_W
#define CON_H	40
#define CON_GAP	0

#define TXT_L_OF  	30
#define TXT_W  		(CON_W - 34)
#define TXT_H		28
#define TXT_T_OF	((CON_H - TXT_H)/2)
#else
#define	W_L     40//210
#define	W_T     60//110
#define	W_W     300//260
#define	W_H     276//420//250

#define TITLE_L  (W_L+10)
#define TITLE_T	 (W_T + 6)
#define TITLE_W  (W_W - 20)
#define TITLE_H  26//26

#define MODE_L  (W_L+10)
#define MODE_T	(W_T+44) //(TITLE_T + TITLE_H + 2)
#define MODE_W  (W_W-20)
#define MODE_H  26//40

#define LST_L	(W_L + 8)
#define LST_T	(MODE_T +  MODE_H)
#define LST_W	(W_W - 35)
#define LST_H	180//(W_H - TITLE_H - MODE_H - 26)//240//200 //180

#define SCB_L (LST_L + LST_W + 4)
#define SCB_T LST_T
#define SCB_W 12
#define SCB_H LST_H-10//(LST_H - 36)

#define CON_L	LST_L
#define CON_T	LST_T
#define CON_W	LST_W
#define CON_H	32
#define CON_GAP	0

#define TXT_L_OF  	30
#define TXT_W  		(CON_W - 34)
#define TXT_H		28
#define TXT_T_OF	((CON_H - TXT_H)/2)

#endif

#define LDEF_CON(root, varCon,nxtObj,ID,IDl,IDr,IDu,IDd,l,t,w,h,conobj,focusID)		\
    DEF_CONTAINER(varCon,root,nxtObj,C_ATTR_ACTIVE,0, \
    ID,IDl,IDr,IDu,IDd, l,t,w,h, CON_SH_IDX,CON_HL_IDX,CON_SL_IDX,CON_GRY_IDX,   \
    audio_item_keymap,audio_item_callback,  \
    conobj, ID,1)
    
#define LDEF_TXT(root,varTxt,nxtObj,l,t,w,h,str)		\
    DEF_TEXTFIELD(varTxt,root,nxtObj,C_ATTR_ACTIVE,0, \
    0,0,0,0,0, l,t,w,h, TXT_SH_IDX,TXT_HL_IDX,TXT_SL_IDX,TXT_GRY_IDX,   \
    NULL,NULL,  \
    C_ALIGN_LEFT | C_ALIGN_VCENTER, 0,0,0,str)

#define LDEF_TITLE(root,varTxt,nxtObj,l,t,w,h,resID)		\
    DEF_TEXTFIELD(varTxt,&root,nxtObj,C_ATTR_ACTIVE,0, \
    0,0,0,0,0, l,t,w,h, TITLE_SH_IDX,TITLE_SH_IDX,TITLE_SH_IDX,TITLE_SH_IDX,   \
    NULL,NULL,  \
    C_ALIGN_CENTER | C_ALIGN_TOP, 6,0,resID,NULL)

#define LDEF_TXT_MODE(root,varTxt,nxtObj,l,t,w,h,resID)		\
    DEF_TEXTFIELD(varTxt,&root,nxtObj,C_ATTR_ACTIVE,0, \
    0,0,0,0,0, l,t,w,h, MODE_SH_IDX,MODE_SH_IDX,MODE_SH_IDX,MODE_SH_IDX,   \
    NULL,NULL,  \
    C_ALIGN_CENTER | C_ALIGN_VCENTER, 0,0,resID,NULL)


#define LDEF_MENU_ITEM(root,varCon,nxtObj,varTxt,ID,IDu,IDd,\
						l,t,w,h,str) \
    LDEF_CON(&root,varCon,nxtObj,ID,ID,ID,IDu,IDd,l,t,w,h,&varTxt,ID)   \
    LDEF_TXT(&varCon,varTxt,NULL,l + TXT_L_OF,t + TXT_T_OF,TXT_W,TXT_H,str)

#define LDEF_LISTBAR(root,varScb,page,l,t,w,h)	\
	DEF_SCROLLBAR(varScb, &root, NULL, C_ATTR_ACTIVE, 0, \
		0, 0, 0, 0, 0, l, t, w, h, LIST_BAR_SH_IDX, LIST_BAR_HL_IDX, LIST_BAR_SH_IDX, LIST_BAR_SH_IDX, \
		NULL, NULL, BAR_VERT_AUTO | SBAR_STYLE_RECT_STYLE, page, LIST_BAR_MID_THUMB_IDX, LIST_BAR_MID_RECT_IDX, \
		0, 10, w, h - 20, 100, 1)

#define LDEF_MARKBMP(root,varBmp,l,t,w,h,icon)		\
  DEF_BITMAP(varBmp,&root,NULL,C_ATTR_ACTIVE,0, \
    0,0,0,0,0, l,t,w,h, MARK_SH_IDX,MARK_HL_IDX,MARK_SL_IDX,MARK_GRY_IDX,   \
    NULL,NULL,  \
    C_ALIGN_CENTER | C_ALIGN_VCENTER, 0,0,icon)

#define LDEF_OL(root,varOl,nxtObj,l,t,w,h,style,dep,count,flds,sb,mark,selary)	\
  DEF_OBJECTLIST(varOl,&root,nxtObj,C_ATTR_ACTIVE,0, \
    1,1,1,1,1, l,t,w,h,LST_SH_IDX,LST_HL_IDX,LST_SL_IDX,LST_GRY_IDX,   \
    audio_list_keymap,audio_list_callback,    \
    flds,sb,mark,style,dep,count,selary)


#define LDEF_WIN(varCon,nxtObj,l,t,w,h,focusID)		\
    DEF_CONTAINER(varCon,NULL,NULL,C_ATTR_ACTIVE,0, \
    0,0,0,0,0, l,t,w,h, WIN_SH_IDX,WIN_HL_IDX,WIN_SL_IDX,WIN_GRY_IDX,   \
    audio_keymap,audio_callback,  \
    nxtObj, focusID,0)



LDEF_TITLE(g_win_audio, audio_title, &audio_txt_mode, \
		TITLE_L, TITLE_T, TITLE_W, TITLE_H, RS_SYSTEM_AUDIO)

LDEF_TXT_MODE(g_win_audio,audio_txt_mode,&audio_ol,\
		MODE_L, MODE_T, MODE_W, MODE_H,0)

LDEF_MENU_ITEM(g_win_audio, audio_item1, &audio_item2,audio_txt1,1,6,2,
		CON_L, CON_T + (CON_H + CON_GAP)*0, CON_W, CON_H,display_strs[0])
LDEF_MENU_ITEM(g_win_audio, audio_item2, &audio_item3,audio_txt2,2,1,3,
		CON_L, CON_T + (CON_H + CON_GAP)*1, CON_W, CON_H,display_strs[1])
LDEF_MENU_ITEM(g_win_audio, audio_item3, &audio_item4,audio_txt3,3,2,4,
		CON_L, CON_T + (CON_H + CON_GAP)*2, CON_W, CON_H,display_strs[2])
LDEF_MENU_ITEM(g_win_audio, audio_item4, &audio_item5,audio_txt4,4,3,5,
		CON_L, CON_T + (CON_H + CON_GAP)*3, CON_W, CON_H,display_strs[3])
LDEF_MENU_ITEM(g_win_audio, audio_item5, &audio_item6,audio_txt5,5,4,6,
		CON_L, CON_T + (CON_H + CON_GAP)*4, CON_W, CON_H,display_strs[4])
LDEF_MENU_ITEM(g_win_audio, audio_item6,NULL             ,audio_txt6,6,5,1,
		CON_L, CON_T + (CON_H + CON_GAP)*5, CON_W, CON_H,display_strs[5])


POBJECT_HEAD audio_list_item[] =
{
	(POBJECT_HEAD)&audio_item1,
	(POBJECT_HEAD)&audio_item2,
	(POBJECT_HEAD)&audio_item3,
	(POBJECT_HEAD)&audio_item4,
	(POBJECT_HEAD)&audio_item5,
	(POBJECT_HEAD)&audio_item6,	
};

LDEF_LISTBAR(audio_ol,audio_scb,6,SCB_L,SCB_T, SCB_W, SCB_H)
//LDEF_LISTBAR(audio_ol,audio_scb,5,SCB_L,SCB_T, SCB_W, SCB_H)

LDEF_MARKBMP(audio_ol,audio_mark, CON_L + 8, CON_T, 20, CON_H, IM_MSELECT/*IM_ICON_SELECT*/);

#define LIST_STYLE (LIST_VER | LIST_SINGLE_SLECT     | LIST_ITEMS_NOCOMPLETE |  LIST_SCROLL | LIST_GRID | LIST_FOCUS_FIRST | LIST_PAGE_KEEP_CURITEM | LIST_FULL_PAGE)

LDEF_OL(g_win_audio,audio_ol,NULL, LST_L,LST_T,LST_W,LST_H,LIST_STYLE, 6, 0,audio_list_item,&audio_scb,(POBJECT_HEAD)&audio_mark,NULL)

LDEF_WIN(g_win_audio, &audio_title,W_L, W_T,W_W,W_H,1)

/*******************************************************************************
*	Local vriable & function declare
*******************************************************************************/

//  Gavim@20141016  ----------- Auto Close Dialog
static ID		winaudio_timer = OSAL_INVALID_ID;
#define PROGNAME_TIMER_NAME 	"winaudio"
//-------------------------------------

static TEXT_FIELD* text_items[] =
{
	&audio_txt1,
	&audio_txt2,
	&audio_txt3,
	&audio_txt4,
	&audio_txt5,
	&audio_txt6,
};
UINT8 win_audio_load(BOOL update);
void win_audio_set_display(void);

void win_audio_change_mode(INT32 shift, BOOL update);
void win_audio_change_pid(void);
void audio_change_pid(int _aud_idx, BOOL b_list_idx);
void win_audio_pid_save(void);
void win_show_not_support(void); //Martin@20150126_audio


static PRESULT 	win_audio_message_proc(UINT32 msg_type, UINT32 msg_code);

// Gavim@20141016
static	UINT8	isDolby[MAX_AUDIO_CNT];

BOOL Select_Doiby = FALSE;	//Martin@20150126_audio
BOOL Select_Enter = FALSE;	//Martin@20150126_audio
//BOOL Default_Audio_set;	//Martin@20150317_audio

#define AUDIO_CHANNEL_NUM_MAX	2

typedef struct
{
	UINT8	a_num;
	UINT8	a_sel;	// current selected audio pid
	UINT16	a_pids[MAX_AUDIO_CNT];
	UINT8	a_lang_num[MAX_AUDIO_CNT];
	UINT16	a_lang[AUDIO_CHANNEL_NUM_MAX][MAX_AUDIO_CNT];
	UINT8	a_type[MAX_AUDIO_CNT];

} audio_info;

//   Gavim@20141016 ----------- Auto Close Dialog
void winaudio_timer_func(UINT unused)
{
	api_stop_timer(&winaudio_timer);
	ap_send_msg(CTRL_MSG_SUBTYPE_CMD_EXIT, 1, TRUE);
	libc_printf("===== Time Out \n");
}
//-----------------------------------------

/* the left and right channel language have the same pid */
static int audio_info_init(UINT8 num, UINT8 sel_idx, UINT16 *pid_list,
						   UINT16 *lang_list, UINT8 *type_list, audio_info *ai)
{
	UINT8 i;
	
	MEMSET(ai, 0, sizeof(audio_info));

	for (i = 0; i < num; ++i)
	{
#ifdef AUDIO_CHANNEL_LANG_SUPPORT
		if ((i > 0) && (pid_list[i] == pid_list[i-1]) &&
			(ai->a_lang_num[ai->a_num-1] < AUDIO_CHANNEL_NUM_MAX))
		{
			ai->a_lang[ai->a_lang_num[ai->a_num-1]][ai->a_num-1] = lang_list[i];
			++ai->a_lang_num[ai->a_num-1];
			continue;
		}
#endif
		ai->a_pids[ai->a_num] = pid_list[i];
		ai->a_lang[0][ai->a_num] = lang_list[i];
		ai->a_lang_num[ai->a_num] = 1;
		ai->a_type[ai->a_num] = type_list[i];
		//CHENGYU_PRINTF("i=%d   a_pids = %d \n" , i,pid_list[i]  );
		//-------------------------
		  // Gavim@20141016
		     isDolby[i] = 0;
			if(AUDIO_TYPE_TEST( pid_list[i],AC3_DES_EXIST))
			{
                         //CHENGYU_PRINTF("Dolby\n"  );
                         isDolby[i] = 1;
			}
              if(AUDIO_TYPE_TEST( pid_list[i],EAC3_DES_EXIST))
			{
                         //CHENGYU_PRINTF("Dolby\n"  );
                         isDolby[i] = 1;
			}	
		
		//-------------------------

          if (sel_idx == i)
          {
            ai->a_sel = ai->a_num;
          }
        ++ai->a_num;
	}
	/*Martin@20150123_audio*/
	UINT j = ai->a_num-1;
	for(i = 0; i < j ; i++)
	{
		if(i > j)
		{
			continue;
		}
		if(isDolby[i] == 1)
		{
			while(isDolby[j] != 0)
			{
				j--;
			}
			isDolby[i] = 0;
			isDolby[j] = 1;
			UINT16 temp = ai->a_pids[i];
			ai->a_pids[i] = ai->a_pids[j];
			ai->a_pids[j--] = temp;
		}
	}

	if(sel_idx == 1 && isDolby[sel_idx])
	{
		Select_Doiby = TRUE;
	}
	else
	{
		Select_Doiby = FALSE;
	}

	//------End Martin

	// CHENGYU_PRINTF("A1 = %d , A2 = %d\n" , isDolby[0] , isDolby[1]   );
	return 0;
}

#ifdef AUDIO_CHANNEL_LANG_SUPPORT

static UINT8 audio_info_real_idx(audio_info *ai, UINT16 pid)
{
	UINT8 i, real_idx;
	
	for (i = 0, real_idx = 0; i < ai->a_num; ++i)
	{
		if (ai->a_pids[i] == pid)
		{
			break;
		}
		real_idx += ai->a_lang_num[i];
	}

	return real_idx;
}

#endif

/*******************************************************************************
*	key mapping and event callback definition
*******************************************************************************/
static VACTION audio_item_keymap(POBJECT_HEAD pObj, UINT32 key)
{
	VACTION act = VACT_PASS;

	return act;
}

static PRESULT audio_item_callback(POBJECT_HEAD pObj, VEVENT event, UINT32 param1, UINT32 param2)
{
	PRESULT ret = PROC_PASS;

	return ret;
}

static VACTION audio_list_keymap(POBJECT_HEAD pObj, UINT32 key)
{
	VACTION act;
    
#ifdef DVR_PVR_SUPPORT
    struct ListInfo rl_info;
    UINT16 play_rl_idx;

    if(api_pvr_is_recording() ||(api_pvr_is_playing() && pvr_info.play.play_handle))
    {
        play_rl_idx = pvr_get_index(pvr_info.play.play_handle);
        pvr_get_rl_info(play_rl_idx, &rl_info);
        if(rl_info.rec_type == 1)
            return VACT_PASS;
    }
    if(api_pvr_is_recording())
    {
    	UINT8 rec_pos;
    	pvr_record_t *rec = api_pvr_get_rec_by_prog_id(pvr_info.play.play_chan_id, &rec_pos);
	if(rec!=NULL)
	{
		pvr_get_rl_info(pvr_get_index(rec->record_handle), &rl_info);
		if(rl_info.rec_type==0x01)
			return VACT_PASS;
	}
    }
#endif

	switch(key)
	{
	case V_KEY_UP:
		act = VACT_CURSOR_UP;
		break;			
	case V_KEY_DOWN:
		act = VACT_CURSOR_DOWN;
		break;			
	case V_KEY_P_UP:
		act = VACT_CURSOR_PGUP;
		break;			
	case V_KEY_P_DOWN:
		act = VACT_CURSOR_PGDN;
		break;
	case V_KEY_ENTER:
		act = VACT_SELECT;
		Select_Enter = TRUE; //Martin@20150126_audio
		break;
	default:
		act = VACT_PASS;
	}

	return act;
}

static PRESULT audio_list_callback(POBJECT_HEAD pObj, VEVENT event, UINT32 param1, UINT32 param2)
{
	PRESULT ret = PROC_PASS;
	UINT16 oldsel,newsel;

	switch(event)
	{
	case EVN_PRE_DRAW:
		win_audio_set_display();
		break;
	case EVN_POST_DRAW:
		break;
	case EVN_ITEM_PRE_CHANGE:
		break;
	case EVN_ITEM_POST_CHANGE:
		break;
	case EVN_PRE_CHANGE:
		break;
	case EVN_POST_CHANGE:
		oldsel = (UINT16)param1;
		newsel = (UINT16)param2;
		if(oldsel!=newsel)
		{
			win_audio_change_pid();
			win_audio_pid_save();
		}
		break;
	default:
		;
	}

	return ret;
}


static VACTION audio_keymap(POBJECT_HEAD pObj, UINT32 key)
{
	VACTION act;

	switch(key)
	{
	case V_KEY_LEFT:
		act = VACT_DECREASE;
		break;
	case V_KEY_RIGHT:
		act = VACT_INCREASE;
		break;
	case V_KEY_EXIT:
	case V_KEY_MENU:
	case V_KEY_AUDIO:
		act = VACT_CLOSE;
		break;
	default:
		act = VACT_PASS;
	}

	return act;

}

static PRESULT audio_callback(POBJECT_HEAD pObj, VEVENT event, UINT32 param1, UINT32 param2)
{
	PRESULT ret = PROC_PASS;
	VACTION unact;

	switch(event)
	{
	case EVN_PRE_OPEN:
		#ifdef SUPPORT_CAS_A
			/* clear msg first */
			api_abel_osd_close_cas_msg();
			on_event_cc_pre_callback();
		#endif
        api_inc_wnd_count();
		if(win_audio_load(FALSE) == 1)
		{
			ret = PROC_LEAVE;
		}
		break;
	case EVN_POST_OPEN:
	    // Gavim@20141016-------------------Auto close dialog
		//winaudio_timer = api_start_timer(PROGNAME_TIMER_NAME, 5000 ,winaudio_timer_func);
         //---------------------------------------------       	
		break;
	case EVN_PRE_CLOSE:
		win_audio_pid_save();
		/*Martin@20150126_audio*/
		if(Select_Doiby && Select_Enter)
		{
			win_show_not_support();
		}
		Select_Enter = FALSE;
		Select_Doiby = FALSE;
		//----End Martin
		break;
	case EVN_POST_CLOSE:
        api_dec_wnd_count();
        //#ifdef SUPPORT_CAS9
        #if defined( SUPPORT_CAS9) ||defined (SUPPORT_CAS7) 
			restore_ca_msg_when_exit_win();
        #endif
	 #ifdef SUPPORT_CAS_A
			on_event_cc_post_callback();
	 #endif		
	    // Gavim@20141016------------------
		//api_stop_timer(&winaudio_timer);	 
		//--------------------------------------------
		break;
	case EVN_UNKNOWN_ACTION:
		unact = (VACTION)(param1>>16);
		if(unact == VACT_DECREASE || unact == VACT_INCREASE)
		{
			win_audio_change_mode((unact == VACT_DECREASE)? -1 : 1, TRUE);
			win_audio_set_display();
			OSD_TrackObject((POBJECT_HEAD)&g_win_audio, C_UPDATE_ALL);
		}
		break;
	case EVN_MSG_GOT:
		ret = win_audio_message_proc(param1,param2);
		break;
		
	}

	return ret;
}


static PRESULT 	win_audio_message_proc(UINT32 msg_type, UINT32 msg_code)
{
	PRESULT	ret = PROC_LOOP;
	OBJLIST *ol = &audio_ol;
	
	switch(msg_type)
	{
	case CTRL_MSG_SUBTYPE_CMD_PIDCHANGE:
		win_audio_load(TRUE);
		win_audio_change_pid();		
		if(menu_stack_get_top() == (POBJECT_HEAD)&g_win_audio)
			OSD_TrackObject((POBJECT_HEAD)ol, C_DRAW_SIGN_EVN_FLG | C_UPDATE_ALL);
        if (msg_code == FALSE)
            win_audio_change_pid();
		break;
    case CTRL_MSG_SUBTYPE_STATUS_AUDIO_TYPE_UPDATE:
		// win_audio_load(TRUE);
		if(menu_stack_get_top() == (POBJECT_HEAD)&g_win_audio)
			OSD_TrackObject((POBJECT_HEAD)ol, C_DRAW_SIGN_EVN_FLG | C_UPDATE_ALL);
        break;
	case CTRL_MSG_SUBTYPE_CMD_EXIT:
			ret = PROC_LEAVE;
		break;
		        
	default:
		ret = PROC_PASS;
	}

	return ret;
}

extern int get_ch_pids(P_NODE* p_node,UINT16* audioPID,UINT16* ttxPID,UINT16* subtPID,UINT32* audioidx);

#ifdef AUDIO_DESCRIPTION_SUPPORT
/* return listed audio index and set @listAudCnt */
static UINT16 realAudIdx2ListAudIdx(UINT16 realAudCnt, UINT8 *audTypeArray,
									UINT16 realAudIdx, UINT16 *listAudCnt)
{
	UINT16 i, _listAduCnt;
	UINT16 listAduIdx = realAudIdx;
	for (i = 0, _listAduCnt = 0; i < realAudCnt; ++i)
	{
		if (!AUDIO_TYPE_IS_AUD_DESC(audTypeArray[i]))
		{
			_listAduCnt++; // main audio
		}
		else if (realAudIdx > i) // audio description
		{
			listAduIdx--;
		}
	}
	if (listAudCnt)
		*listAudCnt = _listAduCnt;
	return listAduIdx;
}

/* return real audio index */
static UINT16 listAudIdx2RealAudIdx(UINT16 realAudCnt, UINT8 *audTypeArray,
									UINT16 listAduIdx)
{
	UINT16 i, tmp;
	for (i = 0, tmp = 0; i < realAudCnt; ++i)
	{
		if (!AUDIO_TYPE_IS_AUD_DESC(audTypeArray[i]))  // main audio
		{
			if (tmp == listAduIdx)
				break;
			else
				tmp++;
		}
	}
	return i;
}
#endif /* AUDIO_DESCRIPTION_SUPPORT */
void win_show_not_support(void)
{
		UINT8 back_saved;	
		win_compopup_init(WIN_POPUP_TYPE_SMSG);
		win_compopup_set_frame(200, 200, 400, 100);
		//win_compopup_set_msg(NULL, NULL,RS_NOMENU_HINT);
		win_compopup_set_msg_ext("Dolby not support !", NULL, 0);			
		win_compopup_open_ext(&back_saved);
		osal_task_sleep(1000);
		win_compopup_smsg_restoreback();	
}		

UINT8 win_audio_load(BOOL update)
{
	UINT8 ret = 0;
	TEXT_FIELD* txt_mode;
	OBJLIST* ol;	
	P_NODE p_node;
	UINT16 i,channel,cnt,sel,top_idx,cur_idx,dep;
	UINT16 audioPID,ttxPID,subtPID;
	UINT32 audioIdx;
	BOOL is_play_rec = FALSE;
	audio_info ai;
	UINT8 audio_type[MAX_PVR_AUDIO_PID > MAX_AUDIO_CNT ? MAX_PVR_AUDIO_PID : MAX_AUDIO_CNT];
	MEMSET(audio_type, 0, sizeof(audio_type));

	txt_mode = & audio_txt_mode;
	ol = &audio_ol;

#ifdef DVR_PVR_SUPPORT
    struct ListInfo rl_info;
    UINT16 play_rl_idx;
    if(api_pvr_is_playing() && pvr_info.play.play_handle)
    {
		play_rl_idx = pvr_get_index(pvr_info.play.play_handle);
        pvr_get_rl_info(play_rl_idx, &rl_info);		
#ifdef AUDIO_DESCRIPTION_SUPPORT
		RET_CODE ret = pvr_get_audio_type(play_rl_idx, audio_type, MAX_PVR_AUDIO_PID);
#endif
		audio_info_init(rl_info.audio_count, rl_info.cur_audio_pid_sel,
			rl_info.multi_audio_pid, rl_info.multi_audio_lang, audio_type, &ai);

		audioIdx = ai.a_sel;
		sel = 0xFFFF;
		cnt = ai.a_num;
#ifdef AUDIO_DESCRIPTION_SUPPORT
		if (ret == RET_SUCCESS)
		{
			audioIdx = realAudIdx2ListAudIdx(ai.a_num, ai.a_type, audioIdx, &cnt);
		}
#endif
/*
#if 0
		if((cnt > 1) && (rl_info.rec_type == 1))
		{
			UINT8 back_saved;
			
			win_compopup_init(WIN_POPUP_TYPE_SMSG);                        
//			win_compopup_set_frame(100, 260, 400, 40);
			win_compopup_set_frame(MSG_POPUP_LAYER_L, MSG_POPUP_LAYER_T, MSG_POPUP_LAYER_W, MSG_POPUP_LAYER_H);
			win_compopup_set_msg_ext("PS playback, single track!", NULL, 0);
			win_compopup_open_ext(&back_saved);
			osal_task_sleep(2000);
			win_compopup_smsg_restoreback();
			
			return 1;
		}
#endif
*/
    }
	else
#endif
	{
		channel = sys_data_get_cur_group_cur_mode_channel();
		get_prog_at(channel,&p_node);
		get_ch_pids(&p_node,&audioPID,&ttxPID,&subtPID,&audioIdx);
#ifdef AUDIO_DESCRIPTION_SUPPORT
		MEMCPY(audio_type, p_node.audio_type, MAX_AUDIO_CNT);
#endif
		audio_info_init(p_node.audio_count, p_node.cur_audio,
			p_node.audio_pid, p_node.audio_lang, audio_type, &ai);
		sel = 0xFFFF;
        cnt = ai.a_num;
#ifdef AUDIO_DESCRIPTION_SUPPORT
		audioIdx = realAudIdx2ListAudIdx(ai.a_num, ai.a_type, ai.a_sel, &cnt);
#else
		audioIdx = ai.a_sel;
#endif
	}

	if(audioIdx < cnt)
		sel= audioIdx;

	dep = OSD_GetObjListPage(ol);	
	cur_idx = 0;
	top_idx = 0;
	if(sel < cnt)
		cur_idx = sel;
	top_idx = cur_idx / dep * dep;
/*
	// Gavim@20141016  ------------------------------
	 //CHENGYU_PRINTF("cur_idx %d   sel %d    \n",  cur_idx , sel );

        if(isDolby[0] == 1)  //   List item1 = Dolby
          if( sel == 0)   // Now menu select is on item1
	        {
	        		//---------------------------------------------
				if (cnt  == 1)   //  Only  have 1 audio
						win_show_not_support();
				else    // Havd 2 audio
				{
						if(isDolby[1] == 0)
						{
							CHENGYU_PRINTF("=== Audio change to channel  2  \n" );
							audio_change_pid(1, TRUE);
							win_audio_pid_save();
							sel = 1;
							//--------------
							win_show_not_support();
						}
						if(isDolby[1] == 1)  // Item1 Item2  all Dolby 
							win_show_not_support();
				}
				//---------------------------------------------
	        }	
*/


	/*Martin@20150126_audio*/

	if(isDolby[1] == 1 )
	{		if( sel == 1)   // Now menu select is on item1
		{
			audio_change_pid(0, TRUE);
			win_audio_pid_save();
			sel = 0;
			cur_idx = 0;
		}
	}

//Martin@20150317_audio
//	if(Default_Audio_set)
//	{
//		Default_Audio_set = FALSE;
//		audio_change_pid(0, TRUE);
//	}
	//---- End Martin
	OSD_SetObjListCount(ol, cnt);
	OSD_SetObjListSingleSelect(ol, sel);	
	OSD_SetObjListTop(ol, top_idx);
	OSD_SetObjListCurPoint(ol, cur_idx);
	OSD_SetObjListNewPoint(ol, cur_idx);	

	win_audio_change_mode(0,FALSE);

	return ret;
}


void win_audio_set_display(void)
{
	TEXT_FIELD *txt;
	OBJLIST* ol;	
	P_NODE p_node;
	UINT16 i,channel,cnt,sel,top_idx,cur_idx,dep,str_len;
	UINT16 audioPID,ttxPID,subtPID;
	UINT16 audioIdx;
	char lang[8];
	char str[30];
	audio_info ai;
	UINT8 audio_type[MAX_PVR_AUDIO_PID > MAX_AUDIO_CNT ? MAX_PVR_AUDIO_PID : MAX_AUDIO_CNT];
	MEMSET(audio_type, 0, sizeof(audio_type));

#ifdef DVR_PVR_SUPPORT
    struct ListInfo rl_info;
    UINT16 play_rl_idx = 0;
	BOOL is_play_rec = FALSE;

    if(api_pvr_is_playing() && pvr_info.play.play_handle)
    {
		play_rl_idx = pvr_get_index(pvr_info.play.play_handle);
        pvr_get_rl_info(play_rl_idx, &rl_info);		
		is_play_rec = TRUE;
    }
#endif

	ol = &audio_ol;

	channel = sys_data_get_cur_group_cur_mode_channel();

	get_prog_at(channel,&p_node);

	cnt = OSD_GetObjListCount(ol);
	dep = OSD_GetObjListPage(ol);	
	top_idx = OSD_GetObjListTop(ol);

	for(i=0;i<dep;i++)
	{
		cur_idx = top_idx + i;		
		txt = text_items[i];

		if(cur_idx < cnt )
		{
#ifdef DVR_PVR_SUPPORT
		    if(is_play_rec)
			{
#ifdef AUDIO_DESCRIPTION_SUPPORT
				RET_CODE ret = pvr_get_audio_type(play_rl_idx, audio_type, MAX_PVR_AUDIO_PID);
#endif
				audio_info_init(rl_info.audio_count, rl_info.cur_audio_pid_sel,
					rl_info.multi_audio_pid, rl_info.multi_audio_lang, audio_type, &ai);

				audioIdx = cur_idx;
#ifdef AUDIO_DESCRIPTION_SUPPORT
				if (ret == RET_SUCCESS)
				{
					audioIdx = listAudIdx2RealAudIdx(ai.a_num, ai.a_type, cur_idx);
				}
#endif
				audioPID = ai.a_pids[audioIdx];
				UINT8 a_channel = (rl_info.audio >> 4) & 0x0F; // audio channel
				MEMSET(lang, 0, sizeof(lang));
				if (a_channel < AUDIO_CHANNEL_NUM_MAX) // left or right channel
				{
					if (ai.a_lang[a_channel][audioIdx] == 0)
						a_channel = 0;
					get_audio_lang3b((UINT8*)&ai.a_lang[a_channel][audioIdx],(UINT8*)&lang[0]);
				}
				else // mono or stereo
				{
					get_audio_lang3b((UINT8*)&ai.a_lang[0][audioIdx],(UINT8*)&lang[0]);
					if ((ai.a_lang_num[audioIdx] > 1) && (ai.a_lang[1][audioIdx] != 0))
					{
						lang[3] = '&';
						get_audio_lang3b((UINT8*)&ai.a_lang[1][audioIdx],(UINT8*)&lang[4]);
					}
				}
		    }
			else
#endif
			{
#ifdef AUDIO_DESCRIPTION_SUPPORT
				MEMCPY(audio_type, p_node.audio_type, MAX_AUDIO_CNT);
#endif
				audio_info_init(p_node.audio_count, p_node.cur_audio,
					p_node.audio_pid, p_node.audio_lang, audio_type, &ai);
				
#ifdef AUDIO_DESCRIPTION_SUPPORT
				audioIdx = listAudIdx2RealAudIdx(ai.a_num, ai.a_type, cur_idx);
#else
				audioIdx = cur_idx;
#endif
				audioPID = ai.a_pids[audioIdx];
				MEMSET(lang,0,sizeof(lang));
				UINT8 a_channel = p_node.audio_channel; // audio channel
				MEMSET(lang, 0, sizeof(lang));
				if (a_channel < AUDIO_CHANNEL_NUM_MAX) // left or right channel
				{
					if (ai.a_lang[a_channel][audioIdx] == 0)
						a_channel = 0;
					get_audio_lang3b((UINT8*)&ai.a_lang[a_channel][audioIdx],(UINT8*)&lang[0]);
				}
				else // mono or stereo
				{
					get_audio_lang3b((UINT8*)&ai.a_lang[0][audioIdx],(UINT8*)&lang[0]);
					if ((ai.a_lang_num[audioIdx] > 1) && (ai.a_lang[1][audioIdx] != 0))
					{
						lang[3] = '&';
						get_audio_lang3b((UINT8*)&ai.a_lang[1][audioIdx],(UINT8*)&lang[4]);
					}
				}

			}
			if(STRLEN(lang) == 0)
				sprintf(str,"Sound %d(%d)",cur_idx + 1,audioPID & 0x1FFF);
			else
				sprintf(str,"%s (%d)",lang,audioPID & 0x1FFF);

			if (audioPID==ai.a_pids[ai.a_sel])
	            key_check_ddplus_stream_changed(&audioPID);

			str_len = STRLEN(str);
			if(AUDIO_TYPE_TEST(audioPID,AC3_DES_EXIST))
				STRCPY(&str[str_len],"[Dolby D]");
            else if(AUDIO_TYPE_TEST(audioPID,EAC3_DES_EXIST))
                STRCPY(&str[str_len],"[Dolby D+]");
			else if(AUDIO_TYPE_TEST(audioPID,AAC_DES_EXIST))
				STRCPY(&str[str_len],"[AAC]");
			else if(AUDIO_TYPE_TEST(audioPID ,ADTS_AAC_DES_EXIST))
				STRCPY(&str[str_len],"[AAC]");
			
			OSD_SetTextFieldContent(txt, STRING_ANSI, (UINT32)str);			
		}
		else
			OSD_SetTextFieldContent(txt, STRING_ANSI, (UINT32)"");
	}
	
}

UINT16 audio_mode_str_ids[] =
{
	RS_AUDIO_MODE_LEFT_CHANNEL,
	RS_AUDIO_MODE_RIGHT_CHANNEL,
	RS_AUDIO_MODE_STEREO,
	RS_AUDIO_MODE_MONO,
};
void win_audio_change_mode(INT32 shift, BOOL update)
{
	TEXT_FIELD* txt_mode;
	OBJLIST* ol;	
	P_NODE p_node;
	UINT16 channel;
	INT32 audio_ch = 0;
	static INT16 temp = 0;
#ifdef DVR_PVR_SUPPORT
    struct ListInfo rl_info;
    UINT16 play_rl_idx;
	UINT8 rec_pos;
	PVR_HANDLE	pvr_handle = (PVR_HANDLE)NULL;
	pvr_record_t *rec;		
#endif
	BOOL update_live_prog = TRUE;
	BOOL update_recording_prog = FALSE;

	txt_mode = & audio_txt_mode;
	ol = &audio_ol;


	if(OSD_GetObjListCount(ol) == 0)
	{
		/*when no audio track, the audio window should also display the content*/
		temp = (temp + shift +4)%4;
		OSD_SetTextFieldContent(txt_mode, STRING_ID, (UINT32)audio_mode_str_ids[temp]);
		if(update)
		OSD_DrawObject((POBJECT_HEAD)txt_mode, C_UPDATE_ALL);
		return;
	}

#ifdef DVR_PVR_SUPPORT
	if(api_pvr_is_playing_hdd_rec())
	{
		// playback recorded file.
		update_recording_prog = TRUE;
		update_live_prog = FALSE;
		pvr_handle = pvr_info.play.play_handle;
	}
	else if(pvr_info.play.play_handle || pvr_info.tms_r_handle || api_pvr_is_recording_cur_prog())
	{
		// tms or playback recording file.
		update_recording_prog = TRUE;
		update_live_prog = TRUE;
		if(pvr_info.play.play_handle)
			pvr_handle = pvr_info.play.play_handle;
		else if(pvr_info.tms_r_handle)
			pvr_handle = pvr_info.tms_r_handle;
		else
		{
			rec = api_pvr_get_rec_by_prog_id(pvr_info.play.play_chan_id, &rec_pos);
			if(rec == NULL)
			{
				ASSERT(0);
			}	
			pvr_handle = rec->record_handle;
		}	
	}
	else
	{
		// only live play
		update_recording_prog = FALSE;
		update_live_prog = TRUE;
	}		
#endif

	if(update_live_prog)
	{
        channel = sys_data_get_cur_group_cur_mode_channel();
    	get_prog_at(channel,&p_node);

    	audio_ch = p_node.audio_channel;
    	audio_ch = ( audio_ch + shift + 4)%4;
    	if(audio_ch != p_node.audio_channel)
    	{
			struct snd_device *snd = dev_get_by_id(HLD_DEV_TYPE_SND, 0);
			chchg_switch_audio_chan(snd, audio_ch);
			p_node.audio_channel = audio_ch;
			modify_prog(p_node.prog_id, &p_node);
			update_data();
		}
	}

#ifdef DVR_PVR_SUPPORT
	if(update_recording_prog && pvr_handle)
	{
		play_rl_idx = pvr_get_index(pvr_handle);
		pvr_get_rl_info(play_rl_idx, &rl_info); 			
		audio_ch = (rl_info.audio>>4)&0x0F;
		audio_ch = (audio_ch + shift + 4)%4;
        if(audio_ch!=((rl_info.audio>>4)&0x0F))
        {
            if(PVR_HANDLE_IS_PLY(pvr_handle))
				pvr_p_switch_audio_channel(pvr_handle, audio_ch);
			rl_info.audio &= 0x0F;
			rl_info.audio |= (audio_ch<<4)&0xF0;
			pvr_set_rl_info(rl_info.index,rl_info);
        }
	}
#endif

	//libc_printf("audio_ch = %d\n",audio_ch);
	//ASSERT(audio_ch < ARRAY_SIZE(audio_mode_str_ids));
	
	OSD_SetTextFieldContent(txt_mode, STRING_ID, (UINT32)audio_mode_str_ids[audio_ch]);
	if(update)
		OSD_DrawObject((POBJECT_HEAD)txt_mode, C_UPDATE_ALL);
}

/* switch audio channel
 *	@_aud_idx: the index of the audio pid to be switch to.
 *			   -1 for the current selected pid index.
 *	@b_list_idx: indentify @_aud_idx is the index of the UI audio list or not.
 */
void audio_change_pid(int _aud_idx, BOOL b_list_idx)
{
	P_NODE p_node;
	UINT16 channel, aud_idx;
	UINT16 audioPID,i;
	INT32 audio_ch;
	audio_info ai;
	UINT8 audio_type[MAX_PVR_AUDIO_PID > MAX_AUDIO_CNT ? MAX_PVR_AUDIO_PID : MAX_AUDIO_CNT];
	MEMSET(audio_type, 0, sizeof(audio_type));

#ifdef NEW_DEMO_FRAME
	struct cc_es_info es;
	struct cc_device_list dev_list;
	struct ts_route_info ts_route;
	INT32 ts_route_id;
	extern P_NODE playing_pnode;
	
	MEMSET(&ts_route, 0, sizeof(struct ts_route_info));
	if (RET_FAILURE == ts_route_get_by_type(TS_ROUTE_MAIN_PLAY, &ts_route_id, &ts_route))
	{
		ts_route_get_by_type(TS_ROUTE_PLAYBACK, &ts_route_id, &ts_route);
	}
#endif

	SYSTEM_DATA *sys_data = NULL;
	aud_idx = (UINT16)_aud_idx;
	
#ifdef DVR_PVR_SUPPORT
	if(api_pvr_is_playing() && pvr_info.play.play_handle)
	{
		struct ListInfo rl_info;
		UINT16 play_rl_idx;
		play_rl_idx = pvr_get_index(pvr_info.play.play_handle);
		pvr_get_rl_info(play_rl_idx, &rl_info);
	#ifdef AUDIO_DESCRIPTION_SUPPORT
		pvr_get_audio_type(play_rl_idx, audio_type, MAX_PVR_AUDIO_PID);
	#endif
		audio_info_init(rl_info.audio_count, rl_info.cur_audio_pid_sel,
			rl_info.multi_audio_pid, rl_info.multi_audio_lang, audio_type, &ai);

	#ifdef AUDIO_DESCRIPTION_SUPPORT
		if (_aud_idx < 0)
		{
			aud_idx = ai.a_sel; // to switch AD on/off
		}
		else if (b_list_idx)
		{
			aud_idx = listAudIdx2RealAudIdx(ai.a_num, ai.a_type, aud_idx);
		}
	#endif	
		if (aud_idx >= ai.a_num)
		{
			AUDIO_DEBUG("%s() invalid audio index: %d >= %d\n", __FUNCTION__, aud_idx, ai.a_num);
			return;
		}
		audioPID = ai.a_pids[aud_idx];
		//libc_printf("switch, playback, audio_count = %d, cur_audio =%d\n",rl_info.audio_count,sel);

	#ifdef NEW_DEMO_FRAME
		audio_ch = (rl_info.audio>>4)&0x0F;
		sys_data = sys_data_get();	
		MEMSET(&es,0,sizeof(es));
		MEMSET(&dev_list,0,sizeof(dev_list));
		es.a_type = AudioPid2Type(audioPID);
		es.spdif_enable = 1;
		es.a_pid = audioPID;
		#ifdef AUDIO_DESCRIPTION_SUPPORT
		es.ad_pid = INVALID_PID;
		if (sys_data_get_ad_service() && sys_data_get_ad_mode())
		{
			// if the playing record is the same with the live recording program
			int adIdx;
			BOOL notify = ((rl_info.prog_number == playing_pnode.prog_number) &&
						   (rl_info.pid_info.pmt_pid == playing_pnode.pmt_pid) &&
			 			   (rl_info.is_recording)) ? FALSE : TRUE;
			 			   	
			//add on 2011-10-20 for the flag to show ad enable when press PIP Key
      extern UINT8 ad_show_flag;
      if(ad_show_flag)
      {
          notify = TRUE;
          ad_show_flag = 0;
      }
                         			   	
			if ((adIdx = aud_desc_select(ai.a_num, ai.a_pids,
					ai.a_lang[0], ai.a_type, aud_idx, notify)) >= 0)
			{
				if (AUDIO_TYPE_IS_BROADCAST_MIXED_AD(ai.a_type[adIdx]))
					es.a_pid = ai.a_pids[adIdx];
				else if (AUDIO_TYPE_IS_RECEIVER_MIXED_AD(ai.a_type[adIdx]))
					es.ad_pid = ai.a_pids[adIdx];
			}
		}
		AD_DEBUG("change audio pid: (0x%X, 0x%X)\n", es.a_pid, es.ad_pid);
		#endif
		es.a_ch = audio_ch;
		es.a_volumn = sys_data->volume;
		dev_list.vpo = dev_get_by_id(HLD_DEV_TYPE_DIS, 0);
		dev_list.vdec = dev_get_by_id(HLD_DEV_TYPE_DECV, 0);
		dev_list.deca = dev_get_by_id(HLD_DEV_TYPE_DECA, 0);
		dev_list.snd_dev = dev_get_by_id(HLD_DEV_TYPE_SND, 0);
		dev_list.dmx = dev_get_by_id(HLD_DEV_TYPE_DMX, ts_route.dmx_id);
		playing_pnode.audio_channel = es.a_ch;
		playing_pnode.audio_volume = es.a_volumn;
#ifdef AUDIO_CHANNEL_LANG_SUPPORT
		playing_pnode.cur_audio = audio_info_real_idx(&ai, ai.a_pids[aud_idx]);
#else
		playing_pnode.cur_audio = aud_idx;
#endif
		chchg_switch_audio_pid(&es, &dev_list);

		if((pvr_info.pvr_state == PVR_STATE_TMS_PLAY) || (pvr_info.pvr_state == PVR_STATE_REC_PLAY))
			api_ci_switch_aid(playing_pnode.prog_id, es.a_pid);
		else
			api_ci_switch_aid(play_rl_idx/*ts_route.prog_id*/, es.a_pid);
	#endif

	#ifdef AUDIO_DESCRIPTION_SUPPORT
		UINT16 pid_list[4];
		pid_list[0] = es.a_pid;
		pid_list[1] = es.ad_pid;
		pvr_p_switch_audio_pid_list(pvr_info.play.play_handle, pid_list);
	#else
		pvr_p_switch_audio_pid(pvr_info.play.play_handle, es.a_pid);
	#endif
	}
	else
#endif	
	{
		channel = sys_data_get_cur_group_cur_mode_channel();
		get_prog_at(channel,&p_node);
#ifdef AUDIO_DESCRIPTION_SUPPORT
		MEMCPY(audio_type, p_node.audio_type, MAX_AUDIO_CNT);
#endif
		audio_info_init(p_node.audio_count, p_node.cur_audio,
			p_node.audio_pid, p_node.audio_lang, audio_type, &ai);
#ifdef AUDIO_DESCRIPTION_SUPPORT
		if (_aud_idx < 0)
		{
			aud_idx = ai.a_sel; // to switch AD on/off
		}
		else if (b_list_idx)
		{
			aud_idx = listAudIdx2RealAudIdx(ai.a_num, ai.a_type, aud_idx);
		}
#endif
		if (aud_idx >= ai.a_num)
		{
			AUDIO_DEBUG("%s() invalid audio index: %d >= %d\n", __FUNCTION__, aud_idx, ai.a_num);
			return;
		}
		audioPID = ai.a_pids[aud_idx];
#ifdef NEW_DEMO_FRAME
		sys_data = sys_data_get();	
		MEMSET(&es,0,sizeof(es));
		MEMSET(&dev_list,0,sizeof(dev_list));
		es.a_type = AudioPid2Type(audioPID);
		es.spdif_enable = 1;
		es.a_pid = audioPID;
	#ifdef AUDIO_DESCRIPTION_SUPPORT
		es.ad_pid = INVALID_PID;
		if (sys_data_get_ad_service() && sys_data_get_ad_mode())
		{
			int adIdx;
			if ((adIdx = aud_desc_select(ai.a_num, ai.a_pids, ai.a_lang[0],
							ai.a_type, aud_idx, TRUE)) >= 0)
			{
				if (AUDIO_TYPE_IS_BROADCAST_MIXED_AD(ai.a_type[adIdx]))
					es.a_pid = ai.a_pids[adIdx];
				else if (AUDIO_TYPE_IS_RECEIVER_MIXED_AD(ai.a_type[adIdx]))
					es.ad_pid = ai.a_pids[adIdx];
			}
		}
		AD_DEBUG("change audio pid: (0x%X, 0x%X)\n", es.a_pid, es.ad_pid);
	#endif
		es.a_ch = p_node.audio_channel;
		es.a_volumn = sys_data->volume;
		dev_list.vpo = dev_get_by_id(HLD_DEV_TYPE_DIS, 0);
		dev_list.vdec = dev_get_by_id(HLD_DEV_TYPE_DECV, 0);
		dev_list.deca = dev_get_by_id(HLD_DEV_TYPE_DECA, 0);
		dev_list.snd_dev = dev_get_by_id(HLD_DEV_TYPE_SND, 0);
        dev_list.dmx = dev_get_by_id(HLD_DEV_TYPE_DMX, ts_route.dmx_id);
		playing_pnode.audio_channel = es.a_ch;
		playing_pnode.audio_volume = es.a_volumn;
    #ifdef AUDIO_CHANNEL_LANG_SUPPORT
		playing_pnode.cur_audio = audio_info_real_idx(&ai, ai.a_pids[aud_idx]);
    #else
		playing_pnode.cur_audio = aud_idx;
    #endif
		chchg_switch_audio_pid(&es, &dev_list);
		api_ci_switch_aid(ts_route.prog_id, es.a_pid);
#else
		UIChChgSwitchAPID(audioPID);
#endif
	}
}

	#ifdef CAS7_PVR_SCRAMBLE
	void Notify_cas_audio_change(UINT8 ); 
	#endif
void win_audio_change_pid(void)
{
	OBJLIST* ol = &audio_ol;
	UINT16 sel;
	
	if (OSD_GetObjListCount(ol) == 0)
		return;

	sel = OSD_GetObjListSingleSelect(ol);
	audio_change_pid(sel, TRUE);
	#ifdef CAS7_PVR_SCRAMBLE
	//Notify_cas_audio_change(1); 
	#endif
}

#ifdef DVR_PVR_SUPPORT
static void win_audio_pid_record_update(UINT32 cur_audio)
{
	struct ListInfo rl_info;
	UINT16 rl_idx;
	UINT8 rec_pos;
	pvr_record_t *rec = (pvr_record_t *)api_pvr_get_rec_by_prog_id(pvr_info.play.play_chan_id, &rec_pos);

	if(pvr_info.play.play_handle)
		rl_idx = pvr_get_index(pvr_info.play.play_handle);
	else if(pvr_info.tms_r_handle)
			rl_idx = pvr_get_index(pvr_info.tms_r_handle);
	else if(rec != NULL)
		rl_idx = pvr_get_index(rec->record_handle);
	else
		return;
		
	pvr_get_rl_info(rl_idx, &rl_info);
	rl_info.cur_audio_pid_sel = cur_audio;
	pvr_set_rl_info(rl_info.index,rl_info);
	pvr_update_rl();
	//libc_printf("switch, save, cur_audio =%d\n", cur_audio);
}
#endif

void win_audio_pid_save(void)
{
	OBJLIST* ol;	
	P_NODE p_node;
	UINT16 channel,sel;
	UINT16 audioPID,ttxPID,subtPID;
	UINT32 audioIdx, realAudIdx;
	audio_info ai;
	UINT8 audio_type[MAX_PVR_AUDIO_PID > MAX_AUDIO_CNT ? MAX_PVR_AUDIO_PID : MAX_AUDIO_CNT];
	MEMSET(audio_type, 0, sizeof(audio_type));
	
	ol = &audio_ol;
	if(OSD_GetObjListCount(ol) == 0)
		return;
	sel = OSD_GetObjListSingleSelect(ol);

#ifdef DVR_PVR_SUPPORT
	// only playback the record, update it to record item.
	if((api_pvr_is_playing_hdd_rec() && pvr_info.play.play_handle))
	{
		realAudIdx = sel;
	    struct ListInfo rl_info;
	    UINT16 play_rl_idx = pvr_get_index(pvr_info.play.play_handle);
        pvr_get_rl_info(play_rl_idx, &rl_info);
#ifdef AUDIO_DESCRIPTION_SUPPORT
		RET_CODE ret = pvr_get_audio_type(play_rl_idx, audio_type, MAX_PVR_AUDIO_PID);
#endif
		audio_info_init(rl_info.audio_count, rl_info.cur_audio_pid_sel,
			rl_info.multi_audio_pid, rl_info.multi_audio_lang, audio_type, &ai);

#ifdef AUDIO_DESCRIPTION_SUPPORT
		if (ret == RET_SUCCESS)
		{
			realAudIdx = listAudIdx2RealAudIdx(ai.a_num, ai.a_type, realAudIdx);
		}
#endif

#ifdef AUDIO_CHANNEL_LANG_SUPPORT
		realAudIdx = audio_info_real_idx(&ai, ai.a_pids[realAudIdx]);
#endif
		win_audio_pid_record_update(realAudIdx);
	}
	else
#endif		
	{
		channel = sys_data_get_cur_group_cur_mode_channel();
		get_prog_at(channel,&p_node);
		get_ch_pids(&p_node,&audioPID,&ttxPID,&subtPID,&audioIdx);
#ifdef AUDIO_DESCRIPTION_SUPPORT
		MEMCPY(audio_type, p_node.audio_type, MAX_AUDIO_CNT);
#endif
		audio_info_init(p_node.audio_count, p_node.cur_audio,
			p_node.audio_pid, p_node.audio_lang, audio_type, &ai);
#ifdef AUDIO_DESCRIPTION_SUPPORT
		realAudIdx = listAudIdx2RealAudIdx(ai.a_num, ai.a_type, sel);
#else
		realAudIdx = sel;
#endif
		if( audioIdx != realAudIdx)
		{
#ifdef AUDIO_CHANNEL_LANG_SUPPORT
			realAudIdx = audio_info_real_idx(&ai, ai.a_pids[realAudIdx]);
#endif
			p_node.cur_audio = realAudIdx;
			p_node.audio_select = 1;
			//libc_printf("modify the node audio cur_audio to %d\n",sel);
			modify_prog(p_node.prog_id, &p_node);
			update_data();	
#ifdef DVR_PVR_SUPPORT
			// check need to update to record item also
			win_audio_pid_record_update(realAudIdx);
#endif		
		}
	}
}

